package com.uinnova.product.eam.service.impl;

import com.alibaba.fastjson.JSON;
import com.binary.core.exception.BinaryException;
import com.binary.core.util.BinaryUtils;
import com.binary.framework.exception.ServiceException;
import com.binary.jdbc.Page;
import com.google.common.collect.Sets;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.comm.model.es.*;
import com.uinnova.product.eam.model.EamArtifactRltVo;
import com.uinnova.product.eam.model.dto.EamHierarchyDto;
import com.uinnova.product.eam.model.dto.EamMultiModelHierarchyDto;
import com.uinnova.product.eam.model.enums.ModelTypeEnum;
import com.uinnova.product.eam.service.EamCategorySvc;
import com.uinnova.product.eam.service.IBmHierarchySvc;
import com.uinnova.product.eam.service.IBmMultiModelHierarchySvc;
import com.uinnova.product.eam.service.IEamArtifactSvc;
import com.uinnova.product.eam.service.es.BmEamMultiModelTypeDao;
import com.uinnova.product.eam.service.es.BmMultiModelHierarchyDao;
import com.uino.api.client.permission.IUserApiSvc;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.permission.base.SysUser;
import com.uino.util.sys.SysUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 多模型层级
 *
 * @author zdh_c
 */
@Service
public class BmMultiModelHierarchySvcImpl implements IBmMultiModelHierarchySvc {
    @Value("${http.resource.space}")
    private String httpResourceUrl;

    private static final int START_NUM = 2;
    private static final int END_NUM = 100;

    @Resource
    BmEamMultiModelTypeDao modelTypeDao;

    @Resource
    BmMultiModelHierarchyDao multiModelHierarchyDao;

    @Resource
    IBmHierarchySvc bmHierarchySvc;

    @Autowired
    private IEamArtifactSvc iEamArtifactSvc;
    @Resource
    private EamCategorySvc categorySvc;
    @Resource
    private IUserApiSvc userApiSvc;

    @Override
    public List<EamMultiModelHierarchy> queryList(Integer releaseState, Integer dataStatus) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        Long domainId = SysUtil.getCurrentUserInfo().getDomainId();
        if(!BinaryUtils.isEmpty(releaseState)){
            queryBuilder.must(QueryBuilders.termQuery("releaseState", releaseState));
        }
        if(!BinaryUtils.isEmpty(dataStatus)){
            queryBuilder.must(QueryBuilders.termQuery("dataStatus", dataStatus));
        }
        queryBuilder.must(QueryBuilders.termQuery("domainId", domainId));
        Page<EamMultiModelHierarchy> modelHierarchyPage = multiModelHierarchyDao.getSortListByQuery(1, 1000, queryBuilder, "modifyTime", false);
        if (BinaryUtils.isEmpty(modelHierarchyPage.getData())) {
            return new ArrayList<>();
        }
        return modelHierarchyPage.getData();
    }

    @Override
    public Page<EamMultiModelHierarchy> queryList(Integer pageNum, Integer pageSize, String like,Integer releaseState, Integer modelType) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        if (!BinaryUtils.isEmpty(like)) {
            List<SysUser> userLike = userApiSvc.getUserInfoByName(like.trim());
            BoolQueryBuilder shouldQuery = QueryBuilders.boolQuery();
            if(!CollectionUtils.isEmpty(userLike)){
                Set<String> nameLists = userLike.stream().map(SysUser::getLoginCode).collect(Collectors.toSet());
                shouldQuery.should(QueryBuilders.termsQuery("creator.keyword", nameLists));
            }
            shouldQuery.should(QueryBuilders.wildcardQuery("creator.keyword", "*" + like.trim() + "*"));
            shouldQuery.should(QueryBuilders.wildcardQuery("name.keyword", "*" + like.trim() + "*"));
            queryBuilder.must(shouldQuery);
        }
        if (!BinaryUtils.isEmpty(releaseState)) {
            queryBuilder.must(QueryBuilders.termQuery("releaseState", releaseState));
        }
        if (!BinaryUtils.isEmpty(modelType)) {
            queryBuilder.must(QueryBuilders.termQuery("modelType", modelType));
        }
        queryBuilder.must(QueryBuilders.termQuery("dataStatus", 1));
        Page<EamMultiModelHierarchy> result = multiModelHierarchyDao.getSortListByQuery(pageNum, pageSize, queryBuilder, "modifyTime", false);
        //图片路径添加ip地址
        if (!BinaryUtils.isEmpty(result.getData())) {
            for (EamMultiModelHierarchy each : result.getData()) {
                String icon = each.getIcrnPath();
                if (icon != null && !icon.startsWith(httpResourceUrl)) {
                    icon = httpResourceUrl + icon;
                    each.setIcrnPath(icon);
                }
            }
        }
        return result;
    }

    @Override
    public Integer flashModuleData(){
        Page<EamMultiModelHierarchy> moduleData = queryList(1, 1000, null, null, null);
        List<EamMultiModelHierarchy> data = moduleData.getData();
        List<EamMultiModelHierarchy> modelList = new ArrayList<>();
        if(!BinaryUtils.isEmpty(data)){
            for (EamMultiModelHierarchy datum : data) {
                Integer releaseState = datum.getReleaseState();
                if(releaseState == 0){
                    datum.setReleaseFlag(false);
                }
                if(releaseState == 1){
                    datum.setReleaseFlag(true);
                }
                modelList.add(datum);
            }
        }
        return multiModelHierarchyDao.saveOrUpdateBatch(modelList);
    }

    @Override
    public Map<Long, EamMultiModelHierarchy> getDataModel() {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        Long domainId = SysUtil.getCurrentUserInfo().getDomainId();
        queryBuilder.must(QueryBuilders.termQuery("modelType", ModelTypeEnum.DATA.val()));
        queryBuilder.must(QueryBuilders.termQuery("domainId", domainId));
        List<EamMultiModelHierarchy> result = multiModelHierarchyDao.getListByQuery(queryBuilder);
        if (BinaryUtils.isEmpty(result)) {
            return Collections.emptyMap();
        }
        return result.stream().collect(Collectors.toMap(EamMultiModelHierarchy::getId, each->each, (k1,k2)->k2));
    }

    @Override
    public Long saveOrUpdate(EamMultiModelHierarchyDto dto) {
        EamMultiModelHierarchy model = EamUtil.copy(dto, EamMultiModelHierarchy.class);
        //校验名称唯一性
        String name = model.getName();
        Long id = model.getId();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery("name.keyword", name));
        boolQuery.must(QueryBuilders.termQuery("dataStatus", 1));
        List<EamMultiModelHierarchy> checkList = multiModelHierarchyDao.getListByQuery(boolQuery);
        long time = BinaryUtils.getNumberDateTime();
        Long domainId = SysUtil.getCurrentUserInfo().getDomainId();
        if (BinaryUtils.isEmpty(id)) {
            //创建
            if (!BinaryUtils.isEmpty(checkList)) {
                throw new ServiceException("建模工艺:" + name + "，已存在");
            }
            model.setCreateTime(time);
            model.setDomainId(domainId);
            model.setReleaseState(0);
        } else {
            if (!BinaryUtils.isEmpty(checkList) && !id.equals(checkList.get(0).getId())) {
                throw new ServiceException("建模工艺:" + name + "，已存在");
            }
            model.setModifyTime(time);
            model.setDomainId(domainId);
        }
        model.setDataStatus(1);
        return multiModelHierarchyDao.saveOrUpdate(model);
    }

    @Override
    public Collection<EamMultiModelType> queryModelTypeList() {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        Long domainId = SysUtil.getCurrentUserInfo().getDomainId();
        boolQuery.must(QueryBuilders.termQuery("domainId", domainId));
        Page<EamMultiModelType> modelTypePage = modelTypeDao.getSortListByQuery(0, 3000, boolQuery, "createTime", false);
        List<EamMultiModelType> data = modelTypePage.getData();
        if(!BinaryUtils.isEmpty(data)){
            //对类型名称去重
            Map<String, EamMultiModelType> collect = data.stream().collect(Collectors.toMap(EamMultiModelType::getName, eamMultiModelType -> eamMultiModelType,(k1,k2)->k1));
            return collect.values();
        }
        return new ArrayList<>();
    }

    @Override
    public Integer saveModelType(List<EamMultiModelType> modelTypeList) {
        Long domainId = SysUtil.getCurrentUserInfo().getDomainId();
        long time = BinaryUtils.getNumberDateTime();
        for (EamMultiModelType eamMultiModelType : modelTypeList) {
            String name = eamMultiModelType.getName();
            if (BinaryUtils.isEmpty(name)) {
                throw new ServiceException("分类名称不能为空！");
            }
            eamMultiModelType.setDomainId(domainId);
            if (BinaryUtils.isEmpty(eamMultiModelType.getCreateTime())) {
                eamMultiModelType.setCreateTime(time);
            }
        }

        return modelTypeDao.saveOrUpdateBatch(modelTypeList);
    }

    @Override
    public Integer deleteModelType(Long id) {
        EamMultiModelType modelType = modelTypeDao.getById(id);
        if (BinaryUtils.isEmpty(modelType)) {
            throw new ServiceException("该模型不存在/已删除!");
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", modelType.getDomainId()));
        long num = modelTypeDao.countByCondition(query);
        if (num <= 1L) {
            throw new ServiceException("模型类型不可为空！");
        }
        //校验模型类型是否被使用
        query.must(QueryBuilders.termQuery("type.id", id));
        boolean existByCondition = multiModelHierarchyDao.existByCondition(query);
        if (existByCondition) {
            throw new ServiceException("模型类型，被使用不允许删除！");
        }
        return modelTypeDao.deleteById(id);
    }

    @Override
    public Long releaseModel(Long modelId) {
        //发布模型树
        EamMultiModelHierarchy model = multiModelHierarchyDao.getById(modelId);
        if (BinaryUtils.isEmpty(model)) {
            throw new ServiceException("该模型不存在/已删除!");
        }
        //校验发布模型树是否存在层级配置
        List<EamHierarchyDto> hierarchyList = bmHierarchySvc.queryByModelId(modelId);
        EamArtifact artifact = new EamArtifact();
        List<EamArtifact> artifactList = iEamArtifactSvc.queryByConditions(artifact);
        Map<Long, EamArtifact> artifactMap = artifactList.stream().collect(Collectors.toMap(EamArtifact::getId, each -> each, (k1, k2) -> k2));
        for (EamHierarchyDto eamHierarchy : hierarchyList) {
            //不是0层
            if (BinaryUtils.isEmpty(eamHierarchy.getArtifactId())) {
                throw new BinaryException("层级配置存在必填项控制，请核实检查。");
            }
            if(eamHierarchy.getDirLvl() == 0 && BinaryUtils.isEmpty(eamHierarchy.getProName())){
                throw new BinaryException("L0层级配置存在必填项控制，请核实检查。");
            }
            EamArtifact vo = artifactMap.get(eamHierarchy.getArtifactId());
            if (BinaryUtils.isEmpty(vo) || vo.getDataStatus()!=1 || vo.getReleaseState()!=1) {
                throw new BinaryException("制品类型未发布/已删除!");
            }

        }
        model.setReleaseState(1);
        model.setReleaseFlag(true);
        //发布层级配置
        return multiModelHierarchyDao.saveOrUpdate(model);
    }

    @Override
    public Long cancelReleaseModel(Long modelId) {
        EamMultiModelHierarchy modelHierarchy = multiModelHierarchyDao.getById(modelId);
        if (BinaryUtils.isEmpty(modelHierarchy)) {
            throw new ServiceException("该模型不存在/已删除!");
        }
        modelHierarchy.setReleaseState(0);
        return multiModelHierarchyDao.saveOrUpdate(modelHierarchy);
    }

    @Override
    public Integer deleteModel(Long modelId) {
        EamMultiModelHierarchy model = multiModelHierarchyDao.getById(modelId);
        Long domainId = SysUtil.getCurrentUserInfo().getDomainId();
        if (BinaryUtils.isEmpty(model)) {
            throw new ServiceException("该模型树不存在/已删除!");
        }
        //添加校验,只要当前模型树被使用就不允许删除
        List<EamCategory> privateCategory = categorySvc.selectByModelId(modelId, LibType.PRIVATE, null);
        List<EamCategory> designCategory = categorySvc.selectByModelId(modelId, LibType.DESIGN, null);
        if(!BinaryUtils.isEmpty(privateCategory) || !BinaryUtils.isEmpty(designCategory)){
            throw new ServiceException("该模型树已被使用,无法删除!");
        }
        //查询层级信息
        model.setDataStatus(0);
        multiModelHierarchyDao.saveOrUpdate(model);
        return 1;
    }

    @Override
    public Integer saveOrUpdateBatch(List<EamMultiModelHierarchy> modelHierarchies) {
        return multiModelHierarchyDao.saveOrUpdateBatch(modelHierarchies);
    }

    @Override
    public EamMultiModelHierarchy getModelById(Long id) {
        EamMultiModelHierarchy model = multiModelHierarchyDao.getById(id);
        if(BinaryUtils.isEmpty(model)){
            return null;
        }
        String icon = model.getIcrnPath();
        if (icon != null && !icon.startsWith(httpResourceUrl)) {
            icon = httpResourceUrl + icon;
            model.setIcrnPath(icon);
        }
        return model;
    }

    @Override
    public Integer copeModel(Long id) {
        EamMultiModelHierarchy model = multiModelHierarchyDao.getById(id);
        if (BinaryUtils.isEmpty(model)) {
            throw new ServiceException("该模型不存在/已删除!");
        }
        //复制模型树
        model.setId(null);
        model.setCreateTime(BinaryUtils.getNumberDateTime());
        model.setReleaseState(0);
        model.setDataStatus(1);
        model.setReleaseFlag(false);
        String copyName = model.getName();
        String key = "-副本";
        //根据模型树id拿到模型树名称-查询 有几个符合条件的模型树名称
        BoolQueryBuilder queryBuilder = new BoolQueryBuilder();
        queryBuilder.must(QueryBuilders.wildcardQuery("name.keyword",copyName+ "*"));
        queryBuilder.must(QueryBuilders.termQuery("dataStatus",1));
        List<EamMultiModelHierarchy> checkList = multiModelHierarchyDao.getListByQuery(queryBuilder);
        //拿到所有的name
        List<String> names = checkList.stream().map(EamMultiModelHierarchy::getName).collect(Collectors.toList());
        if (!names.contains(copyName + key)) {
            //如果不包含key，表示是第一次复制；
            model.setName(copyName+key);
        } else {
            Set<Integer> set = new HashSet<>(names.size());
            String prefix = copyName + key;
            Pattern pattern = Pattern.compile("(" + prefix + "\\(\\d+\\))");
            Set<String> regexSet = getTemplateRegexSet(names, pattern);
            //符合正则表达式的取出来遍历；
            for (String name : regexSet) {
                String s = name.substring(name.lastIndexOf("(") + 1, name.lastIndexOf(")"));
                int num = Integer.parseInt(s);
                set.add(num);
            }
            if (BinaryUtils.isEmpty(set)) {
                model.setName(copyName + key + "(" + 2 + ")");
            }else{
                for (int i = START_NUM; i < END_NUM; i++) {
                    if (!set.contains(i)) {
                        model.setName(copyName + key + "(" + i + ")");
                        break;
                    }
                }
            }
        }

        Long modelId = multiModelHierarchyDao.saveOrUpdate(model);
        //查询层级信息
        List<EamHierarchyDto> hierarchyList = bmHierarchySvc.queryByModelId(id);
        List<EamHierarchy> copyHierarchy = new ArrayList<>();
        for (EamHierarchyDto eamHierarchyDto : hierarchyList) {
            EamHierarchy hierarchy = EamUtil.copy(eamHierarchyDto, EamHierarchy.class);
            List<EamArtifactRltVo> rltList = eamHierarchyDto.getRltList();
            if(!BinaryUtils.isEmpty(rltList)){
                hierarchy.setRltList(JSON.toJSONString(rltList));
            }
            hierarchy.setId(null);
            hierarchy.setModelId(modelId);
            copyHierarchy.add(hierarchy);
        }
        return bmHierarchySvc.saveOrUpdateBatch(copyHierarchy);
    }
    @Override
    public Set<String> getTemplateRegexSet(List<String> inputList, Pattern p) {
        Set<String> templateParamSet = Sets.newHashSet();
        for (String input : inputList) {
            Matcher m = p.matcher(input);
            while (m.find()) {
                String key = m.group(1);
                templateParamSet.add(key);
            }
        }
        return templateParamSet;
    }

    @Override
    public List<EamMultiModelHierarchy> getModelByIds(Set<Long> ids) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termsQuery("id", ids));
        queryBuilder.must(QueryBuilders.termQuery("dataStatus", 1));
        List<EamMultiModelHierarchy> modelHierarchies = multiModelHierarchyDao
                .selectListByQuery(1, 3000, queryBuilder);
        for (EamMultiModelHierarchy multiModelHierarchy : modelHierarchies) {
            String icon = multiModelHierarchy.getIcrnPath();
            if (icon != null && !icon.startsWith(httpResourceUrl)) {
                icon = httpResourceUrl + icon;
                multiModelHierarchy.setIcrnPath(icon);
            }
        }
        return modelHierarchies;
    }

}
